<?php

namespace common\jobs\base;

use Yii;
use Throwable;
use yii\helpers\ArrayHelper;

/**
 * Interval Retry Job Exception.
 *
 * Throws when serialized message cannot be unserialized to a job.
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class IntervalRetryJobException extends \Exception {

    /**
     * 触发类型
     */
    const TRIGGER_FULL_DAY = 0;
    const TRIGGER_FAST = 1;

    /**
     * @var integer 默认触发类型：全天24小时
     */
    private $_triggerType = self::TRIGGER_FULL_DAY;

    /**
     * @var string 支持的触发类型选项
     */
    protected $triggerOptions = [
        self::TRIGGER_FULL_DAY => [15, 180, 600, 1800, 1800, 3600, 7200, 21600, 54000],
        self::TRIGGER_FAST => [1, 2, 3, 4, 5, 6, 7, 8, 9],
    ];

    /**
     * @var IntervalRetryableJob|null
     */
    private $_job = null;

    /**
     * @param string $trigger 触发类型
     * @param IntervalRetryableJob $job 间隔类型任务
     * @param mixed $message
     * @param int $code
     * @param Throwable|null $previous
     */
    public function __construct($trigger = 0, $job = null, $message = '', $code = 0, Throwable $previous = null) {
        if ($job instanceof IntervalRetryableJob) {
            $this->_triggerType = $trigger;
            $this->_job = $job;
        }
        parent::__construct($message, $code, $previous);
    }

    /**
     * 间隔通知类任务
     * @return IntervalRetryableJob|null
     */
    final public function getJob() {
        return $this->_job;
    }

    /**
     * 获取间隔时间表
     * @return array of serialized message that cannot be unserialized to a job
     */
    final public function getDurations() {
        $innerType = $this->_triggerType;
        if (isset($this->triggerOptions[$innerType])) {
            return $this->triggerOptions[$innerType];
        }
        return array_shift($this->triggerOptions);
    }

    /**
     * 返回缓存执行次数
     * @param IntervalRetryableJob $job
     * @return integer
     */
    public function getAttempt($job) {
        $cache = Yii::$app->cache;
        $prefix = $job->getUniqueCacheId();
        $attempt = intval($cache->get($prefix)) + 1;
        $cache->set($prefix, $attempt);
        return $attempt;
    }

    /**
     * 获取延迟时间（秒）
     * @return integer
     */
    public function getDelay() {
        $job = $this->getJob();
        $attempt = $this->getAttempt($job);
        $durations = $this->getDurations();
        return ArrayHelper::getValue($durations, $attempt, false);
    }

}
